// $Id: native_type.cpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#define XPCOM_API_VERSION 1090000 // supress warning

#include <xpcom/config.hpp>
#include <limits.h>
#include <boost/limits.hpp>
#include <boost/type_traits/is_same.hpp>
#include <xpcom/types.hpp>
#include <xpgen/model.hpp>
#include <xpgen/native_type.hpp>
#include <xpgen/output_cpp.hpp>

namespace xpgen {

native_type::native_type() :
    enable(false),
    auto_config(true)
{
}

void native_type::init_output(output_cpp& output)
{
    if (enable) {
        // Auto configurations
        if (auto_config) {
            //  8-bit types
            if (sizeof(char) == 1) {
                if (type_int8.empty()) {
                    if (boost::is_same<xpcom::int8_t, signed char>::value)
                        type_int8 = "signed char";
                    else if (boost::is_same<xpcom::int8_t, char>::value)
                        type_int8 = "char";
                }

                if (type_uint8.empty()) {
                    if (boost::is_same<xpcom::uint8_t, unsigned char>::value)
                        type_uint8 = "unsigned char";
                    else if (boost::is_same<xpcom::uint8_t, char>::value)
                        type_uint8 = "char";
                }
            }

            //  16-bit types
            if (sizeof(short) == 2) {
                if (type_int16.empty() && boost::is_same<xpcom::int16_t, short>::value)
                    type_int16 = "short";
                if (type_uint16.empty() && boost::is_same<xpcom::uint16_t, unsigned short>::value)
                    type_uint16 = "unsigned short";
            }

            // 32-bit types
            if (sizeof(int) == 4) {
                if (type_int32.empty() && boost::is_same<xpcom::int32_t, int>::value)
                    type_int32 = "int";
                if (type_uint32.empty() && boost::is_same<xpcom::uint32_t, unsigned>::value)
                    type_uint32 = "unsigned";
            }

            if (sizeof(long) == 4) {
                if (type_int32.empty() && boost::is_same<xpcom::int32_t, long>::value)
                    type_int32 = "long";
                if (type_uint32.empty() && boost::is_same<xpcom::uint32_t, unsigned long>::value)
                    type_uint32 = "unsigned long";
            }

            // 64-bit types
#ifdef BOOST_HAS_LONG_LONG
            if (sizeof(long long) == 8) {
                if (type_int64.empty() && boost::is_same<xpcom::int64_t, long long>::value)
                    type_int64 = "long long";
                if (type_uint64.empty() && boost::is_same<xpcom::uint64_t, unsigned long long>::value)
                    type_uint64 = "unsigned long long";
            }
#endif

#if ULONG_MAX != 0xFFFFFFFF
            if (sizeof(long) == 8) {
                if (type_int64.empty() && boost::is_same<xpcom::int64_t, long>::value)
                    type_int64 = "long";
                if (type_uint64.empty() && boost::is_same<xpcom::uint64_t, unsigned long>::value)
                    type_uint64 = "unsigned long";
            }
#endif

#ifdef BOOST_HAS_MS_INT64
            if (sizeof(__int64) == 8) {
                if (type_int64.empty() && boost::is_same<xpcom::int64_t, __int64>::value)
                    type_int64 = "__int64";
                if (type_uint64.empty() && boost::is_same<xpcom::uint64_t, unsigned __int64>::value)
                    type_uint64 = "unsigned __int64";
            }
#endif

            // XXX float, double, char, pstring(char*)
            // These are already native types by default

            // wchar_t, pwstring(wchar_t*)
            if (sizeof(wchar_t) == 2 && boost::is_same<xpcom::wchar, wchar_t>::value) {
                if (type_wchar.empty())
                    type_wchar = "wchar_t";
                if (type_pwstring.empty())
                    type_pwstring = "wchar_t*";
            }

            // XXX size_t, since xpcom::size_t is defined to be std::size_t, so
            if (type_size.empty())
                type_size = "std::size_t";
        }

        // Now set them
        output.native_types[type_decl::tag_int8] = type_int8;
        output.native_types[type_decl::tag_int16] = type_int16;
        output.native_types[type_decl::tag_int32] = type_int32;
        output.native_types[type_decl::tag_int64] = type_int64;
        output.native_types[type_decl::tag_uint8] = type_uint8;
        output.native_types[type_decl::tag_uint16] = type_uint16;
        output.native_types[type_decl::tag_uint32] = type_uint32;
        output.native_types[type_decl::tag_uint64] = type_uint64;
        output.native_types[type_decl::tag_float] = type_float;
        output.native_types[type_decl::tag_double] = type_double;
        output.native_types[type_decl::tag_char] = type_char;
        output.native_types[type_decl::tag_wchar] = type_wchar;
        output.native_types[type_decl::tag_pstring] = type_pstring;
        output.native_types[type_decl::tag_pwstring] = type_pwstring;
        output.native_types[type_decl::tag_size] = type_size;
    }
}

} // namespace xpgen
